package org.ace.logic.raid.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.ace.logic.raid.protocol.RaidProtocol.*;
import javax.annotation.Resource;

import io.netty.channel.Channel;

import org.ace.basicdata.IBasicDataCentral;
import org.ace.basicdata.model.MonsterBasicData;
import org.ace.basicdata.model.PlayerBasicData;
import org.ace.basicdata.model.RaidBasicData;
import org.ace.dao.model.Player;
import org.ace.endingCode.SocketModel;
import org.ace.event.AceEventUtils;
import org.ace.event.model.RaidOverEvent;
import org.ace.logic.AbstractHandlerServImpl;
import org.ace.logic.IHandlerServ;
import org.ace.logic.map.model.MoveDTO;
import org.ace.logic.raid.dto.AttackDTO;
import org.ace.logic.raid.dto.EnteredDTO;
import org.ace.logic.raid.dto.HarmDTO;
import org.ace.logic.raid.dto.HarmResultDTO;
import org.ace.logic.raid.dto.M_atk_DTO;
import org.ace.logic.raid.dto.MonsterModelDB;
import org.ace.logic.raid.dto.TargetChgeDTO;
import org.ace.logic.raid.protocol.RaidProtocol;
import org.ace.logic.user.dto.PlayerDTO;
import org.ace.model.MonsterModel;
import org.ace.model.Vector3;
import org.ace.protocol.Protocol;
import org.ace.tool.ISchedule;
import org.ace.tool.ISkillProcess;
import org.ace.tool.impl.PropertyUtil;
import org.codehaus.groovy.transform.powerassert.Value;

public class RaidHandlerServImpl extends AbstractHandlerServImpl implements
		IHandlerServ {

	@Resource(name="eventUtils")
	private AceEventUtils eventUtils;
	
	@Resource(name="raidBasicDataCenteral")
	private IBasicDataCentral<RaidBasicData> raidBasicDataCenteral;
	
	@Resource(name="monsterBasicDataCenteral")
	private IBasicDataCentral<MonsterBasicData> monsterBasicDataCenteral;
	
	@Resource(name="playerBasicDataCenteral")
	private IBasicDataCentral<PlayerBasicData> playerBasicDataCenteral ;
	
	@Resource(name="schedule")
	private ISchedule schedule;
	
	/*技能 key 基础值*/
	@Resource(name="skillProcessMap")
	private Map<Integer,ISkillProcess> skillProcessMap;
	
	/*怪物map
	 * */
	private Map<Integer ,MonsterModelDB> monsters=new ConcurrentHashMap<Integer, MonsterModelDB>();
	
	private AtomicInteger key=new AtomicInteger(-1);
	
	/*起始坐标*/
	private Vector3 startPosition;
	
	private Map<Integer ,Vector3> userPosition =new ConcurrentHashMap<Integer, Vector3>();
	
	private Map<Integer , MoveDTO> moveList=new ConcurrentHashMap<Integer, MoveDTO>();
	
	private AtomicInteger playerCount=new AtomicInteger(0);
	
	private AtomicBoolean isOver=new AtomicBoolean(false);
	
	@Override
	public int getType()
	{
		return Protocol.TYPE_RAID;
	}
	
	public void init(int raidCode)
	{
		//获取副本基本数据
		RaidBasicData data=raidBasicDataCenteral.get(raidCode);
		startPosition = data.getStarPostion();
		for(MonsterModel model :data.getMonsters())
		{
			//通过脚本管理器 获取指定gdCode的怪物 基本数据 将之 转换成 MonsterModelDB 数据
			MonsterModelDB monster=new MonsterModelDB(monsterBasicDataCenteral.get(model.getGdCode()) ,model.getLevel(),model.getX(),model.getY(),model.getZ());
			//等级 等用 策划算法给出 ，给定 怪物key
		    monster.id=key.getAndDecrement();
		    //注册怪物 
		    monsters.put(monster.id, monster);
		}
		
		moveSync();
	}
	//数据同步与延迟队列 
	private void moveSync() {
		schedule.schedule(new Runnable() {
			
			@Override
			public void run() {
				if(moveList.size()>0)
				{
					brocast(RaidProtocol.MOVE_BRO, moveList.values().toArray());
					moveList.clear();
				}
				if(!isOver.get())
				{
					moveSync();
				}
			}
		}, 200);
		
	}

	@Override
	protected void process(Channel channel, SocketModel message) {
		switch(message.getCommand())
		{
		case ENTERED_CREQ:
			enter(channel);
			break;
		case MOVE_CREQ:
			move(channel,message);
			break;
		case LEAVE_CREQ:
			leave(channel);
			break;
		case TALK_CREQ:
			talk(channel,message);
			break;
		case ATTACK_CREQ:
			attack(channel,message);
			break;
		case HARM_CREQ:
			harm(channel,message);
			break;
		case TARGET_CHANGE_CREQ:
			targetChange(channel,message);
			break;
		case TARGET_NULL_CREQ:
			targetRemove(channel,message);
			break;
		case M_ATK_CREQ:
			m_Atk(channel ,message);
			break;
		}

	}

	private void m_Atk(Channel channel, SocketModel<Integer> message) {
		Integer userId=getUserId(channel);
		Integer m_id=message.getMessage();
		//服务器中存在 此怪物
		if(monsters.containsKey(m_id))
		{
			MonsterModelDB monster=monsters.get(m_id);
			Player player=playerBiz.get(userId);
			if(player.getHp()<=0)
			{//被怪物攻击的玩家 没血了 群发 怪物失去目标 
				brocast(TARGET_NULL_BRO, m_id);
				return;
			}
			
			//返回 怪物伤害数值
			int harm =monster.atk*10-player.getDef()*5;
			//计算伤害后 的剩余生命值
			int value=player.getHp()-harm >= 0 ? player.getHp()-harm : 0;
			
			player.setHp(value);
			if(value==0)
			{
				playerCount.getAndDecrement();
				if(playerCount.get()==0)
				{//结束副本,// 0表示 角色死亡
					raidOver(0);
				}
			}
			//群发被怪物 攻击的玩家伤害
			brocast(M_ATK_BRO, new M_atk_DTO(m_id,userId,harm,value>0));
		}
		
	}

	/**0 表示角色死亡 1标示 副本胜利*/
	private void raidOver(int type) {
		if(!isOver.get())
		{
			isOver.set(true);
			RaidOverEvent event=new RaidOverEvent(this, getArea());
			eventUtils.DispatchEvent(event);
			brocast(RAID_OVER_SRES,type);
		}
		
	}

	private void targetRemove(Channel channel, SocketModel<Integer> message) {
		Integer userId=getUserId(channel);
		Integer m_id=message.getMessage();
		//副本存在此怪
		if(monsters.containsKey(m_id))
		{
			MonsterModelDB monster=monsters.get(m_id);
			
			if(userId.equals(monster.target))
			{
				monster.target=-1;
				brocast(TARGET_NULL_BRO,m_id);//群发 目标丢失
			}
		}
		
	}

	private void targetChange(Channel channel, SocketModel<Integer> message) {
		Integer userId=getUserId(channel);
		Integer m_id=message.getMessage();
		//副本存在此怪
		if(monsters.containsKey(m_id))
		{
			MonsterModelDB monster=monsters.get(m_id);
			//目标已挂
			if(playerBiz.get(userId).getHp()<=0)  return;
			//无目标 则跟踪当前玩家
			if(monster.target==-1)
			{
				monster.target=userId;
				brocast(TARGET_CHANGE_BRO,new TargetChgeDTO(userId, m_id));//群发 目标丢失
			}
			else
			{//已有目标 ， 所锁定的的目标是由单个客户端 发送过来后 给target 赋值锁定 ，没有的时候定会要 定 -1
				brocast(TARGET_CHANGE_BRO,new TargetChgeDTO(monster.target, m_id));//群发 目标丢失
			}
		}
		
	}

	private void harm(Channel channel, SocketModel<HarmDTO> message) {
		Integer userId=getUserId(channel);
		HarmDTO dto=message.getMessage();
		
		//判断角色有没有这个技能
		Player player=playerBiz.get(userId);
		int[] skills=playerBasicDataCenteral.get(player.getUserjob()).getSkills();
		for(int i: skills)
		{
			//技能 或是 普通攻击
			if(i==dto.skillCode || dto.skillCode==-1 || dto.skillCode==-2)
			{
				/**给客户端返回的 伤害列表*/
				List<HarmResultDTO> results=new ArrayList<HarmResultDTO>();
				
				//遍历所有被攻击的怪物计算伤害
				for(int m_id :dto.monsters)
				{
					//当前副本里 有这个 怪物
					if(monsters.containsKey(m_id))
					{
						/**每一个的 伤害计算结果*/
						HarmResultDTO result=new HarmResultDTO();
						//获取技能信息
						ISkillProcess obj= skillProcessMap.get(dto.skillCode);
					   //获取副本里面的 单个怪物信息
						MonsterModelDB monster=monsters.get(m_id);
						int harm = obj.process(player, monster);
						
						logger.debug(userId+" 对怪物"+m_id+"造成伤害"+harm);
						
						//改变怪物数值
						monster.hp-=harm;
						result.m_id=m_id;
						result.value =harm;
						//已死亡改变数值
						if(monster.hp<= 0)
						{
							result.isDie= true;
							monsters.remove(m_id);//怪物已死亡分配经验值
							result.exp=monster.exp;
						}
						
						//增加当前副本玩家经验值
						for(Player p : getRoles())
						{
							//每个玩家获取多少经验 有专门的算法给出，如果升级了发送升级 消息
							if(playerBiz.addExp(p.getUserid(), monster.exp))
							{							
								brocast(LEVEL_UP_SRES, p.getId());
							}
						}
						//所有 返回造成伤害的
						results.add(result);
					}
				}
				if(results.size() > 0)
				{
					//pvp 的话 将 怪物换成 角色
					//群发给客户端 有怪物受到伤害
					brocast(HARM_BRO, results.toArray());
				}
				if(monsters.size()==0)
				{
					//通知客户端副本结束 胜利了
					raidOver(1);
				}
				break;
			}
		}
	}

	private void attack(Channel channel, SocketModel<Integer> message) {
		Integer userId =getUserId(channel);
		//发起一次攻击 群发其他客户端 做视图表现
		brocast(channel ,ATTACK_BRO,new AttackDTO(userId,message.getMessage()));	
	}

	private void talk(Channel channel, SocketModel<String> message) {
		brocast(TALK_BRO, message.getMessage());		
	}
    
	public void enter(Channel channel)
	{
		Integer userId = getUserId(channel);
		//没进入的话
		if(!enterd(userId))
		{
			super.enter(channel);
			//群发给其他玩家 当前玩家进入
			PlayerDTO player = new PlayerDTO(getRole(userId));
			player.x=startPosition.x;
			player.y=startPosition.y;
			player.z=startPosition.z;
			
			brocast(channel, ENTERED_BRO, player);
		}
		
		playerCount.getAndIncrement();
		//发送给客户端 副本数据
		// 直接返回 当前副本数据给玩家
		
		userPosition.put(userId, new Vector3(startPosition.x, startPosition.y, startPosition.z));
	
		EnteredDTO dto=new EnteredDTO();
		//存储要传输的怪物数据
		MonsterModelDB[] mms=new MonsterModelDB[monsters.size()];
		monsters.values().toArray(mms);
		dto.monsters=mms;
		dto.players=getDTOs(getRoles());
		//给客户端发送  副本玩家和怪物数据
		write(channel, ENTERED_SRES, dto);
	}
	
	private PlayerDTO[] getDTOs(Player[] players) {
		PlayerDTO[] dtos=new PlayerDTO[players.length];
		for(int i=0;i< dtos.length; i++)
		{
			Vector3 v = userPosition.get(players[i].getId());
			dtos[i] =new PlayerDTO(players[i]);
			dtos[i].x=v.x;
			dtos[i].y=v.y;
			dtos[i].z=v.z;
					
		}
		return dtos;
	}

	private void move(Channel channel, SocketModel<MoveDTO> message) {
		final Integer userId= getUserId(channel);
		final MoveDTO move =message.getMessage();
		userPosition.put(userId, new Vector3(move.position.x, move.position.y, move.position.z));
		move.userId = userId;//加入延迟队列
		moveList.put(userId, move);		
	}

	@Override
	protected void channelClose(Channel channel) {
		leave(channel);
	}
	
	public boolean leave(Channel channel)
	{
		super.leave(channel);
		Integer userId=getUserId(channel);
			userPosition.remove(userId);
		return true;
	}

}
